
#include "pong.h"
#include "osCamerahandler.h"


pong::pong(osCamerahandler *camera,colorHandler *colors)
{
	this->camera = camera;
	this->colors = colors;
	field  = *(new ofRectangle(1, 0, 796, 599));
	
	gameOn = true;
	resetGame();
	padIsCircle = 1;
	aispeed = 9;
	lastHitTime = time(NULL)-1;
}


pong::~pong(void)
{

}
void pong::stopGame(){
	leftPoints = 0;
	rightPoints = 0;
	resetBall();
	ballDirection.set(0, 0);
}
void pong::startGame(){
	ai1 = field.height;
	ai2 = 0;
	ballDirection.set(0.6f, 0.4f);
}
void pong::resetGame() {
	stopGame();
	startGame();
}

void pong::resetBall() {
	lasthit = noborder;
	int halfWayx = field.x+field.width/2;
	int halfWayy = field.y+field.height/2;
	ballmultiplier = 3;
	ball.set(halfWayx, halfWayy);
}

void pong::update()
{
	

	int halfWay = field.y+field.width/2;

	



	if(camera->trackedBlobs.size()<2) {
		ai1 +=min(aispeed,abs(ball.y-ai1))*(ball.y<ai1 ? -1 : 1);
		ai2 +=min(aispeed,abs(ball.y-ai2))*(ball.y<ai2 ? -1 : 1);
		
		
		ofCvTrackedBlob a = ofCvTrackedBlob();
		a.center = ofPoint(200, ai1, 0);
		ofCvTrackedBlob b = ofCvTrackedBlob();
		b.center = ofPoint(500, ai2, 0);

		if(camera->trackedBlobs.size()== 0)
		{
			camera->trackedBlobs.push_back(b);
			camera->trackedBlobs.push_back(a);
		}	
		else if(camera->trackedBlobs.size()== 1) 
		{
			if(camera->trackedBlobs[0].center.x<field.width/2)
				camera->trackedBlobs.push_back(b);
			else
				camera->trackedBlobs.push_back(a);
		}
	}

	pads.clear();

	for(int i = 0;i < camera->trackedBlobs.size();i++) {
		if(camera->trackedBlobs[i].center.x < halfWay) {
			pads.push_back(*(new ofPoint(field.x, camera->trackedBlobs[i].center.y, 0)));
		}
		else {
			pads.push_back(*(new ofPoint(field.x+field.width, camera->trackedBlobs[i].center.y, 0)));
		}
	}
	if(lastHitTime<time(NULL))
		ball += ballDirection*ballmultiplier;

	if(lasthit != bottomborder && ball.y+ballRadius > field.y+field.height) {
		ballDirection.y = -ballDirection.y;
		lasthit = bottomborder;
	}
	if(lasthit != topborder && ball.y-ballRadius < field.y) {
		ballDirection.y = -ballDirection.y;
		lasthit = topborder;
	}

	for(int i = 0;i < pads.size();i++) {
		if(collisionWithRectPad(i) && !padIsCircle) {
			ballDirection.x = -ballDirection.x;
		}
		else if(collisionWithCirclePad(i) && padIsCircle ) {
			setNewBallVector(i);
		}

	}

	if(ball.x+ballRadius > field.x+field.width) {
		lastHitTime = time(NULL)+3;
		rightPoints++;
		resetBall();
		ball.set(field.x+field.width-ballRadius,field.height/2);
		ballDirection.set(-ofRandom(0.6f,0.97f),ofRandom(0.1f,0.5f));
	}
	if(ball.x-ballRadius < field.x) {
		lastHitTime = time(NULL)+3;
		leftPoints++;
		resetBall();
		ball.set(field.x+ballRadius,field.height/2);
		ballDirection.set(ofRandom(0.6f,0.97f),ofRandom(0.1f,0.5f));
	}
	ballDirection.normalize();
}

void pong::draw(int screenoffset) {
	

	if(lastHitTime<time(NULL))
	{
	//Draw circle
	ofSetColor(colors->foregroundcolor);
	for(int i=0;i<10;i++)
		ofCircle(screenoffset+ball.x, ball.y, ballRadius*(1-i*0.02f));
	
	ofFill();
	ofSetColor(colors->fillcolor);
	ofCircle(screenoffset+ball.x, ball.y, ballRadius*(1-10*0.02f));
	}

	for(int i = 0;i < pads.size();i++) {
		if(padIsCircle)
		{
			ofSetColor(colors->foregroundcolor);
			for(int j=0;j<10;j++)
				ofCircle(screenoffset+pads[i].x, pads[i].y, padWidth*(1-j*0.015f));

			ofLine(screenoffset+pads[i].x, pads[i].y, screenoffset+ball.x, ball.y);
			ofLine(screenoffset+pads[i].x, pads[i].y+1, screenoffset+ball.x, ball.y+1);
			ofLine(screenoffset+pads[i].x, pads[i].y-1, screenoffset+ball.x, ball.y-1);

			ofCircle(screenoffset+pads[i].x, pads[i].y, padWidth*(1-10*0.015f));
			
			ofFill();
			ofSetColor(colors->fillcolor);
			ofCircle(screenoffset+pads[i].x, pads[i].y, padWidth*(1-10*0.015f));
		}
			
		else
			ofRect(screenoffset+pads[i].x-(padWidth/2), pads[i].y-(padHeight/2), padWidth, padHeight);

	}

    ostringstream leftstring;
	leftstring  << leftPoints << endl;
	ofDrawBitmapString( leftstring.str(), field.x+(field.width/4*1),40);  

    ostringstream rightstring;
	rightstring  << rightPoints << endl;
	ofDrawBitmapString( rightstring.str(), field.x+(field.width/4*3),40);  
}

bool pong::collisionWithRectPad(int padNo)  {
	double circleDistance_x;
	double circleDistance_y;

	double x = pads[padNo].x - padWidth/2;
	double y = pads[padNo].y - padWidth/2;


	circleDistance_x = abs(ball.x - x - padWidth/2);
    circleDistance_y = abs(ball.y - y - padHeight/2);

    if (circleDistance_x > (padWidth/2 + ballRadius)) { return false; }
    if (circleDistance_y > (padWidth/2 + ballRadius)) { return false; }

    if (circleDistance_x <= (padWidth/2)) { return true; } 
    if (circleDistance_y <= (padHeight/2)) { return true; }

    double cornerDistance = sqrt((double)(pow((circleDistance_x - padWidth/2), 2) +
                          pow((circleDistance_y - padHeight/2), 2)));

    return (cornerDistance <= ballRadius);

}

bool pong::collisionWithCirclePad(int padNo)  {
	double x = pads[padNo].x;
	double y = pads[padNo].y;

	double distance = sqrt(pow((x - ball.x), 2) + pow((y - ball.y), 2));


    return (distance <= ballRadius+padWidth);

}

void pong::setNewBallVector(int padNo) {

	// Get the normal vector on the line we want to bounce on
	// Which is the vector between ball center and pad center
	double x = pads[padNo].x;
	double y = pads[padNo].y;

	int side = (x > field.width/2 ? rightborder : leftborder);
	if(side == lasthit){ return; }
	lasthit = side;
	cout << "Detected bounce on " << (x > 600 ? "right side" : "left side") << endl;

	ofxVec2f normalVector = ofxVec2f(ball.x, ball.y)-ofxVec2f(x, y);

	float nn = normalVector.dot(normalVector);
	float vn = normalVector.dot(ofxVec2f(ballDirection.x, ballDirection.y));
	
	if (vn > 0.0f) return ; // no bounce, else ball will stick to monster.
	
	ballmultiplier+=0.25f;

	cout << ballmultiplier << endl;
	
	ofxVec2f v = ((2.0f * (vn / nn)) * normalVector); // reflect along the collision plane.
	
	cout << "calced new direction" << endl;
	
	ofxVec2f b = ofxVec2f(ballDirection.x-v.x,ballDirection.y-v.y);
	b.normalize();
	if(abs(b.x)<0.6f)
	{
		float h = (0.6f/abs(b.x));
		b.x*=h;
	}
	if(abs(b.y)<0.1f)
	{
		float h = (0.1f/abs(b.y));
		b.y*=h;
	}
	b.normalize();
	ballDirection = ofPoint(b.x,b.y,0);


	


}